package com.sec.android.app.myfiles.dialog;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.provider.Settings;
import android.support.design.widget.TextInputLayout;
import android.text.Editable;
import android.text.InputFilter;
import android.text.InputType;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;


import com.sec.android.app.myfiles.R;
import com.sec.android.app.myfiles.feature.KnoxMgr;
import com.sec.android.app.myfiles.info.AppConstants;
import com.sec.android.app.myfiles.info.AppFeatures;
import com.sec.android.app.myfiles.log.Log;
import com.sec.android.app.myfiles.operation.ProgressListener;
import com.sec.android.app.myfiles.util.EmoticonUtils;
import com.sec.android.app.myfiles.widget.EditTextEx;

import java.util.regex.Pattern;

public class EditTextDialogFragment extends AbsDialogFragment implements ProgressListener, OnFocusChangeListener {

    private static final String DIALOG_TAG = "edit_text_dialog";

    private static final String ARGS_TITLE_RES_ID = "args_title_res_id";
    private static final String ARGS_OK_TEXT_RES_ID = "args_ok_text_res_id";
    private static final String ARGS_DEFAULT_STRING = "args_default_string";
    private static final String ARGS_INITIAL_SELECTION_POSITION = "args_initial_selection_position";
    private static final String ARGS_POSTFIX = "args_postfix";
    private static final String ARGS_EXCEED_INPUT_LENGTH = "args_exceed_input_length";
    private static final String ARGS_INITIAL_STATE_OF_OK = "args_initial_state_of_ok";
    private static final String ARGS_INPUT_TYPE = "args_input_type";
    private static final String ARGS_EXTRA_IME_OPTION = "args_input_type";
    private static final String ARGS_INPUT_VALUE_MINIMUM = "args_input_value_minimum";
    private static final String ARGS_INPUT_VALUE_MAXIMUM = "args_input_value_maximum";
    private static final String ARGS_INPUT_UNIT = "args_input_unit";

    private static final int DEFAULT_INPUT_TYPE = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;

    private EditTextEx mEditText;
    private TextView mInputUnitView;
    private TextInputLayout mInputLayout;
    private IntentFilter mKeyboardIntentFilter;
    private boolean mIsKeyboardVisible = true;
    private long mReceiveTime;
    private int mResTitleString;
    private int mResOKBtnString;
    private String mDefaultText;
    private EditTextCallback mCallback;
    private boolean mIsFilledMaxLength;
    private boolean mIsInvalidText;
    private boolean mShowError = false;
    private AlertDialog mDialog;
    private int mInitialSelectionPos;
    private String mPostfix;
    private boolean mIsExceedInputLength = false;
    private boolean mEnableDone = true;
    private int mInputType = DEFAULT_INPUT_TYPE;
    private String mExtraImeOptions = null;
    private String mMinimumValue = null;
    private String mMaximumValue = null;
    private String mInputUnit = null;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        ensureArguments();
    }

    private void ensureArguments() {
        Bundle args = getArguments();
        if (args != null) {
            mResTitleString = args.getInt(ARGS_TITLE_RES_ID, R.string.app_name);
            mResOKBtnString = args.getInt(ARGS_OK_TEXT_RES_ID, R.string.ok);
            mDefaultText = args.getString(ARGS_DEFAULT_STRING);
            mInitialSelectionPos = args.getInt(ARGS_INITIAL_SELECTION_POSITION,
                    !TextUtils.isEmpty(mDefaultText) ? mDefaultText.length() : 0);
            mPostfix = args.getString(ARGS_POSTFIX);
            mIsExceedInputLength = args.getBoolean(ARGS_EXCEED_INPUT_LENGTH, false);
            mEnableDone = args.getBoolean(ARGS_INITIAL_STATE_OF_OK, true);
            mInputType = args.getInt(ARGS_INPUT_TYPE, DEFAULT_INPUT_TYPE);
            mExtraImeOptions = args.getString(ARGS_EXTRA_IME_OPTION, "");
            mMinimumValue = args.getString(ARGS_INPUT_VALUE_MINIMUM, null);
            mMaximumValue = args.getString(ARGS_INPUT_VALUE_MAXIMUM, null);
            mInputUnit = args.getString(ARGS_INPUT_UNIT, null);
        }
    }

    private void setEditTextCallback(EditTextCallback callback) {
        mCallback = callback;
    }

    public void show(FragmentManager fragmentManager) {
        if (fragmentManager != null) {
            show(fragmentManager, DIALOG_TAG);
        }
    }

    public void showAllowingStateLoss(FragmentManager fm, final String tag) {
        if (fm != null) {
            final FragmentTransaction t = fm.beginTransaction();
            t.add(this, tag);
            t.commitAllowingStateLoss();
        }
    }

    @Override
    protected Dialog _createDialog() {
        final Activity activity = getActivity();

        View rootView = LayoutInflater.from(activity).inflate(R.layout.edit_text_dialog_input_layout, null);

        mEditText = (EditTextEx) rootView.findViewById(R.id.text_input);
        mInputLayout = (TextInputLayout) rootView.findViewById(R.id.text_input_wrapper);
        mInputUnitView = (TextView) rootView.findViewById(R.id.edit_text_unit);
        mDialog = new AlertDialog.Builder(activity).setView(rootView).setTitle(mResTitleString).setPositiveButton(mResOKBtnString, null)
                .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int arg1) {
                        dialog.cancel();
                        dismissAllowingStateLoss();
                    }
                }).create();

        setEditTextAttribute();
        setInputUnit();
        return mDialog;
    }

    @Override
    public void onResume() {
        super.onResume();

        checkTextEmpty();
        checkDefaultNameAndNameExist();

        final Activity activity = getActivity();
        if (mEditText != null) {
            if (mEditText.isCursorVisible()) {
                mEditText.setCursorVisible(true);
            }
            if (mIsKeyboardVisible && !KnoxMgr.getInstance(mContext).isKnoxKeyguardShown(mContext)) {
                mEditText.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if (activity != null) {
                            InputMethodManager keyboard = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
                            //TODO HYL 输入法
                            /*
                            if (!keyboard.semIsAccessoryKeyboard()) {
                                keyboard.showSoftInput(mEditText, InputMethodManager.SHOW_IMPLICIT);
                            } else {
                                keyboard.semForceHideSoftInput();
                            }
                            */
                        }
                    }
                }, AppFeatures.SIP_APPEARANCE_DELAY);
            }

            mEditText.setOnFocusChangeListener(this);

            if (mKeyboardIntentFilter == null) {
                mKeyboardIntentFilter = new IntentFilter();
                mKeyboardIntentFilter.addAction("ResponseAxT9Info");
            }
            activity.getApplicationContext().registerReceiver(mKeyboardReceiver, mKeyboardIntentFilter);

            if (mInputLayout.isErrorEnabled()) {
                updatePositiveButton();
            }

            if (mEditText.length() >= AppConstants.MAX_INPUT_LENGTH) {
                if (mIsFilledMaxLength && mShowError) {
                    setInputErrorEnabled(true);
                    setInputError(getString(R.string.max_char_reached_msg, AppConstants.MAX_INPUT_LENGTH));
                }
                mIsFilledMaxLength = true;
            } else {
                mIsFilledMaxLength = false;
            }
        }

        if (!mEnableDone) {
            setButtonEnabled(mDialog.getButton(DialogInterface.BUTTON_POSITIVE), mEnableDone);
            mEnableDone = true;
        }
    }

    @Override
    public void onPause() {
        if (System.currentTimeMillis() - mReceiveTime < 150) {
            mIsKeyboardVisible = true;
        }

        if (mKeyboardReceiver != null) {
            getActivity().getApplicationContext().unregisterReceiver(mKeyboardReceiver);
        }
        super.onPause();
    }

    @Override
    public void onCancel(DialogInterface dialog) {
        if (mCallback != null) {
            mCallback.onCancel(getActivity());
        }
        super.onCancel(dialog);
    }

    @Override
    public void onStart() {
        super.onStart();

        Button btn = mDialog.getButton(AlertDialog.BUTTON_POSITIVE);
        btn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View arg0) {
                if (mCallback != null) {
                    mCallback.onOK(getInputSting(), getActivity());
                    updatePositiveButton();
                }
            }
        });
    }

    @Override
    public void onFinished(boolean bRet, String msg, Bundle extras) {
        dismiss();
    }

    @Override
    public void onProgressChanged(String fileName, int progress, int total) {
        // DON'T need IMPLEMENT
    }

    private void updatePositiveButton() {
        Button btn = mDialog.getButton(AlertDialog.BUTTON_POSITIVE);
        String text = getInputSting();

        mEditText.setBackgroundTintList(getResources().getColorStateList(R.color.color_primary, null));
        boolean bEnable = (!text.isEmpty());
        if (btn != null) {
            if (!isHighContrastFontOn()) {
                setInputErrorEnabled(false);
            } else {
                setInputErrorEnabled(true);
            }
            if (bEnable && !mCallback.checkText(text, getActivity())) {
                bEnable = false;
            }
            btn.setClickable(bEnable);
            setButtonEnabled(btn, bEnable);
        }
    }

    private String getInputSting() {
        String ret = "";
        if (mEditText != null) {
            ret = mEditText.getText().toString().trim();
            ret = ret.replaceAll("\n", " ");
        }
        return ret;
    }

    private void initPositiveButton() {
        Button btn = mDialog.getButton(AlertDialog.BUTTON_POSITIVE);
        if (mEditText.length() >= AppConstants.MAX_INPUT_LENGTH) {
            setInputErrorEnabled(true);
            setInputError(getString(R.string.max_char_reached_msg, AppConstants.MAX_INPUT_LENGTH));
        } else if (mIsInvalidText) {
            setInputErrorEnabled(true);
            setInputError(getString(R.string.invalid_character));
        } else if (mMinimumValue != null && mMaximumValue != null) {
            String currentInputString = getInputSting();
            if (currentInputString != null && !TextUtils.isEmpty(currentInputString)) {
                Integer inputValue = Integer.valueOf(mMaximumValue + 1);
                try {
                    inputValue = Integer.valueOf(currentInputString);
                } catch (NumberFormatException e) {
                    Log.e(this, "NumberFormatException : " + e.toString());
                }
                if (inputValue < Integer.valueOf(mMinimumValue)) {
                    mEditText.setTextKeepState(mMinimumValue);
                    setInputErrorEnabled(true);
                    setInputError(getString(R.string.input_value_exceed_range, mMinimumValue, mMaximumValue));
                } else if (inputValue > Integer.valueOf(mMaximumValue)) {
                    mEditText.setTextKeepState(mMaximumValue);
                    setInputErrorEnabled(true);
                    setInputError(getString(R.string.input_value_exceed_range, mMinimumValue, mMaximumValue));
                }
            }
        } else {
            setInputErrorEnabled(false);
        }
        setButtonEnabled(btn, true);
    }

    private void checkDefaultNameAndNameExist() {
        Button btn = mDialog.getButton(AlertDialog.BUTTON_POSITIVE);
        if (getInputSting().equals(mDefaultText) && mCallback.checkNameExist(getInputSting())) {
            btn.setClickable(false);
            setButtonEnabled(btn, false);
        }
    }

    private void checkTextEmpty() {
        Button btn = mDialog.getButton(AlertDialog.BUTTON_POSITIVE);
        String text = getInputSting();
        boolean isEmpty = TextUtils.isEmpty(text);

        btn.setClickable(true);

        if (!isHighContrastFontOn()) {
            setButtonEnabled(btn, !isEmpty);
        } else if (isHighContrastFontOn() && isEmpty) {
            btn.setClickable(false);
        }
    }

    private boolean isHighContrastFontOn() {
        boolean bRet = false;
        ContentResolver cr = mDialog.getContext().getContentResolver();
        if (Settings.Secure.getInt(cr, AppConstants.HIGH_TEXT_CONTRAST_DISABLED, 0) ==
                AppConstants.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED)
            bRet = true;
        return bRet;
    }

    private void setEditTextAttribute() {
        setInputErrorEnabled(false);
        mEditText.setPostfix(mPostfix);
        mEditText.setText(mDefaultText);
        mEditText.setSelection(0, mInitialSelectionPos);
        mEditText.setInputType(mInputType);
        if (mInputType == DEFAULT_INPUT_TYPE) {
            mEditText.setPrivateImeOptions(AppConstants.ImeOptions.EMOTICON_OFF + ";" +
                    AppConstants.ImeOptions.SYMBOL_OFF + ";" + mExtraImeOptions);
        } else if (mInputType == InputType.TYPE_CLASS_NUMBER) {
            mEditText.setPrivateImeOptions(AppConstants.ImeOptions.NUMBERPAD_ONLY);
        }

        if (mIsExceedInputLength) {
            mIsFilledMaxLength = true;
            mShowError = true;
        }

        mEditText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                initPositiveButton();
            }

            @Override
            public void afterTextChanged(Editable s) {
                checkTextEmpty();
                checkDefaultNameAndNameExist();

                if (s.length() >= AppConstants.MAX_INPUT_LENGTH) {
                    if (!mIsFilledMaxLength && !mShowError) {
                        setInputErrorEnabled(true);
                        setInputError(getString(R.string.max_char_reached_msg, AppConstants.MAX_INPUT_LENGTH));
                        mShowError = true;
                    }
                    mIsFilledMaxLength = true;
                } else {
                    mIsFilledMaxLength = false;
                }
            }
        });

        mEditText.setFilters(new InputFilter[]{
                new InputFilter() {
                    @Override
                    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dStart, int dEnd) {
                        Pattern ps = Pattern.compile("[\\*/\\\\\\?:<>\\|\"]+");
                        if (ps.matcher(source).find() || EmoticonUtils.hasEmoticon(source)) {
                            setInputErrorEnabled(true);
                            if (!mIsFilledMaxLength) {
                                setInputError(getString(R.string.invalid_character));
                                mIsInvalidText = true;
                            } else {
                                setInputError(getString(R.string.max_char_reached_msg, AppConstants.MAX_INPUT_LENGTH));
                                mShowError = true;
                            }

                            return dest.subSequence(dStart, dEnd);
                        } else {
                            if (!mIsFilledMaxLength) {
                                setInputErrorEnabled(false);
                            }
                            mIsInvalidText = false;
                        }
                        return source;
                    }
                },
                new InputFilter.LengthFilter(AppConstants.MAX_INPUT_LENGTH) {
                    @Override
                    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dStart, int dEnd) {
                        CharSequence rst = super.filter(source, start, end, dest, dStart, dEnd);
                        if (rst != null && !mShowError) {
                            mIsFilledMaxLength = true;
                            setInputErrorEnabled(true);
                            setInputError(getString(R.string.max_char_reached_msg, AppConstants.MAX_INPUT_LENGTH));
                            mShowError = true;
                        } else {
                            if (!mIsFilledMaxLength && !mIsInvalidText) {
                                setInputErrorEnabled(false);
                                mShowError = false;
                            }
                        }
                        return rst;
                    }
                }});

        mEditText.setOnEditorActionListener(new OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                if (actionId == EditorInfo.IME_ACTION_DONE) {
                    // If click 'Done' button in keyboard, just hide keyboard.
                    InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
                    imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
                    return true;
                }
                return false;
            }
        });

        mEditText.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View view, int i, KeyEvent keyEvent) {
                if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
                    // If 'Enter' key is pressed using BT Keyboard, positive button should be clicked.
                    Button button = mDialog.getButton(AlertDialog.BUTTON_POSITIVE);
                    button.callOnClick();
                }
                return false;
            }
        });
    }

    private void setInputUnit() {
        if (mInputUnitView != null && mInputUnit != null) {
            mInputUnitView.setText(mInputUnit);
            mInputUnitView.setVisibility(View.VISIBLE);
        }
    }

    @Override
    public void onFocusChange(View arg0, boolean arg1) {
        final Activity activity = getActivity();
        if (activity != null) {
            InputMethodManager keyboard = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
            //TODO HYL 输入法
            /*
            if (keyboard.semIsAccessoryKeyboard() || KnoxMgr.getInstance(mContext).isKnoxKeyguardShown(mContext)) {
                keyboard.semForceHideSoftInput();
            }
            */
        }
    }

    @Override
    public void dismissByBroadcast() {
        super.dismissByBroadcast();
        if (mCallback != null) {
            mCallback.onCancel(getActivity());
        }
    }

    public void setInputErrorEnabled(boolean error) {
        if (!error && mEditText != null) {
            mEditText.setBackgroundTintList(getResources().getColorStateList(R.color.color_primary, null));
        }
        mInputLayout.setErrorEnabled(error);
    }

    public void setInputError(String msg) {
        mInputLayout.setError(msg);
    }

    private void setButtonEnabled(Button btn, boolean enabled) {
        btn.setEnabled(enabled);
        btn.setFocusable(enabled);
    }


    private final BroadcastReceiver mKeyboardReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            mReceiveTime = System.currentTimeMillis();
            mIsKeyboardVisible = intent.getBooleanExtra("AxT9IME.isVisibleWindow", true);
        }
    };


    public interface EditTextCallback {
        boolean checkNameExist(String inputString);

        boolean checkText(String inputString, Activity activity);

        void onOK(String inputString, Activity activity);

        void onCancel(Activity activity);
    }

    public static class Builder {
        Bundle mArgs;
        EditTextCallback mCallback;

        public Builder() {
            mArgs = new Bundle();
        }

        public EditTextDialogFragment build() {
            EditTextDialogFragment dialog = new EditTextDialogFragment();
            dialog.setArguments(new Bundle(mArgs));
            if (mCallback != null) {
                dialog.setEditTextCallback(mCallback);
            }
            return dialog;
        }

        public Builder setEditTextCallback(EditTextCallback callback) {
            mCallback = callback;
            return this;
        }

        public Builder setTitle(int titleResId) {
            mArgs.putInt(ARGS_TITLE_RES_ID, titleResId);
            return this;
        }

        public Builder setOkText(int textResId) {
            mArgs.putInt(ARGS_OK_TEXT_RES_ID, textResId);
            return this;
        }

        public Builder setDefaultText(String defaultText) {
            mArgs.putString(ARGS_DEFAULT_STRING, defaultText);
            return this;
        }

        public Builder setInitialSelectionPosition(int position) {
            mArgs.putInt(ARGS_INITIAL_SELECTION_POSITION, position);
            return this;
        }

        public Builder setPostfix(String postfix) {
            mArgs.putString(ARGS_POSTFIX, postfix);
            return this;
        }

        public Builder setExceedInputLength(boolean isExceed) {
            mArgs.putBoolean(ARGS_EXCEED_INPUT_LENGTH, isExceed);
            return this;
        }

        public Builder setInitialStateOfOk(boolean enabled) {
            mArgs.putBoolean(ARGS_INITIAL_STATE_OF_OK, enabled);
            return this;
        }

        public Builder setInputType(int inputType) {
            mArgs.putInt(ARGS_INPUT_TYPE, inputType);
            return this;
        }

        public Builder setInputRange(String Minimum, String Maximum) {
            mArgs.putString(ARGS_INPUT_VALUE_MINIMUM, Minimum);
            mArgs.putString(ARGS_INPUT_VALUE_MAXIMUM, Maximum);
            return this;
        }

        public Builder setInputUnit(String unit) {
            mArgs.putString(ARGS_INPUT_UNIT, unit);
            return this;
        }

        public Builder setExtraImeOptions(String ExtraImeOptions) {
            mArgs.putString(ARGS_EXTRA_IME_OPTION, ExtraImeOptions);
            return this;
        }
    }
}
